package monitor

import (
	"fmt"
	"gitee.com/ymofen/gobase"
	"runtime"
	"sync/atomic"
	"time"
)

type MonitorSpeedN struct {
	CurrN     atomic.Int64
	LastT     time.Time
	LastN     int64
	LastSpeed int64
	Id        string
}

func NewMonitorSpeedN() *MonitorSpeedN {
	rval := &MonitorSpeedN{}
	monitorAliveN.Add(1)
	runtime.SetFinalizer(rval, func(obj interface{}) {
		monitorAliveN.Add(-1)
	})
	rval.Reset()
	AddMonitor(rval)
	return rval
}

func (this *MonitorSpeedN) Calcu() {
	currN := this.CurrN.Load()
	defer func() {
		this.LastN = currN
		this.LastT = time.Now()
	}()
	ms := time.Since(this.LastT).Milliseconds()
	n := currN - this.LastN
	if ms == 0 || n == 0 {
		this.LastSpeed = 0
		return
	}
	this.LastSpeed = n * 1000 / ms
}

func (this *MonitorSpeedN) Delta(n int64) {
	this.CurrN.Add(n)
}

func (this *MonitorSpeedN) Reset() {
	this.CurrN.Store(0)
	this.LastN = 0
	this.LastSpeed = 0
	this.LastT = time.Now()
}

func (this *MonitorSpeedN) Close() error {
	RemoveMonitor(this)
	return nil
}

func (this *MonitorSpeedN) Info() string {
	return fmt.Sprintf("%d(s) %d", this.LastSpeed, this.CurrN.Load())
}

type MonitorSpeedSizeRec struct {
	CurrSize      atomic.Int64
	CurrN         atomic.Int64
	LastSize      int64
	LastSpeedSize int64
	LastCalcT     time.Time

	LastN      int64
	LastSpeedN int64

	LastSpeedCalcuInfo string
}

var (
	monitorAliveN atomic.Int64
)

func GetMonitorAliveN() int64 {
	return monitorAliveN.Load()
}

func NewMonitorSpeedSize() *MonitorSpeedSizeRec {
	rval := &MonitorSpeedSizeRec{}
	monitorAliveN.Add(1)
	runtime.SetFinalizer(rval, func(obj interface{}) {
		monitorAliveN.Add(-1)
	})
	rval.Reset()
	AddMonitor(rval)
	return rval
}

func (this *MonitorSpeedSizeRec) Delta(n int64) {
	this.CurrSize.Add(n)
	this.CurrN.Add(1)
}

func (this *MonitorSpeedSizeRec) Close() error {
	RemoveMonitor(this)
	return nil
}

func (this *MonitorSpeedSizeRec) DeltaBuf(data []byte) {
	this.Delta(int64(len(data)))
}

func (this *MonitorSpeedSizeRec) Calcu() {
	currSize := this.CurrSize.Load()
	currN := this.CurrN.Load()

	defer func() {
		this.LastSize = currSize
		this.LastN = currN
		this.LastCalcT = time.Now()
	}()
	ms := time.Since(this.LastCalcT).Milliseconds()
	n := currN - this.LastN
	if ms == 0 || n == 0 {
		this.LastSpeedN = 0
		this.LastSpeedSize = 0
		return
	}
	size_v := currSize - this.LastSize
	this.LastSpeedN = n * 1000 / ms
	this.LastSpeedSize = size_v * 1000 / ms
}

func (this *MonitorSpeedSizeRec) Reset() {
	this.CurrN.Store(0)
	this.LastN = 0
	this.LastSpeedN = 0
	this.CurrSize.Store(0)
	this.LastSize = 0
	this.LastSpeedSize = 0
	this.LastCalcT = time.Now()
}

func (this *MonitorSpeedSizeRec) Info() string {
	return fmt.Sprintf("size: %s(s) %s, io:%d(s) %d", gobase.HumanFilesize(this.LastSpeedSize), gobase.HumanFilesize(this.CurrSize.Load()), this.LastSpeedN, this.CurrN.Load())
}
